package com.aube.guide.views;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;

import com.aube.guide.AnimationFactory;
import com.aube.guide.AnimationListener;
import com.aube.guide.GuideConstants;
import com.aube.guide.OnGuidePerformedListener;
import com.aube.guide.PreferencesManager;
import com.aube.guide.Target;

/**
 * Created by huyaonan on 16/6/22.
 */
public abstract class BaseGuideView extends RelativeLayout {

    /**
     * Mask color
     */
    protected int maskColor;

    /**
     * dragGuideView will start
     * showing after delayMillis seconds
     * passed
     */
    protected long delayMillis;

    /**
     * We don't draw dragGuideView
     * until isReady field set to true
     */
    protected boolean isReady;

    /**
     * Show/Dismiss dragGuideView
     * with fade in/out animation if
     * this is enabled.
     */
    protected boolean isFadeAnimationEnabled;

    /**
     * Animation duration
     */
    protected long fadeAnimationDuration;

    /**
     * Target View
     */
    protected Target targetView;

    protected Target mainView;

    /**
     * Handler will be used to
     * delay dragGuideView
     */
    protected Handler handler;

    /**
     * Circle padding
     */
    protected int padding;

    /**
     * Layout width/height
     */
    protected int width;
    protected int height;

    /**
     * Dismiss on touch any position
     */
    protected boolean dismissOnTouch;

    /**
     * Info dialog will be shown
     * If this value true
     */
    protected boolean isInfoEnabled;

    /**
     * Image View will be shown if
     * this is true
     */
    protected int imageRes;

    /**
     * Save/Retrieve status of dragGuideView
     * If Intro is already learnt then don't show
     * it again.
     */
    protected PreferencesManager preferencesManager;

    /**
     * Check using this Id whether user learned
     * or not.
     */
    protected String dragGuideViewId;

    /**
     * When layout completed, we set this true
     * Otherwise onGlobalLayoutListener stuck on loop.
     */
    protected boolean isLayoutCompleted;

    protected int displayTime = 0;

    /**
     * Notify user when dragGuideView is dismissed
     */
    protected OnGuidePerformedListener mPerformedListener;

    /**
     * Perform click operation to target
     * if this is true
     */
    protected boolean isPerformClick;

    public BaseGuideView(Context context) {
        this(context, null);
    }

    public BaseGuideView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BaseGuideView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        setWillNotDraw(false);
        setVisibility(INVISIBLE);

        /**
         * set default values
         */
        maskColor = GuideConstants.DEFAULT_MASK_COLOR;
        delayMillis = GuideConstants.DEFAULT_DELAY_MILLIS;
        fadeAnimationDuration = GuideConstants.DEFAULT_FADE_DURATION;
        padding = GuideConstants.DEFAULT_TARGET_PADDING;
        isReady = false;
        isFadeAnimationEnabled = true;
        dismissOnTouch = false;
        isLayoutCompleted = false;
        isInfoEnabled = false;
        isPerformClick = false;

        /**
         * initialize objects
         */
        handler = new Handler();

        preferencesManager = new PreferencesManager(context);

        init();
    }

    abstract protected void init();
    abstract protected void drawGuide(Canvas canvas);
    abstract protected void showInfo();

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
        if (Build.VERSION.SDK_INT < 16) {
            v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
        } else {
            v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        width = getMeasuredWidth();
        height = getMeasuredHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        drawGuide(canvas);
    }

    /**
     * Perform click operation when user
     * touches on target circle.
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                dismiss();
                return false;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * Shows material view with fade in
     * animation
     *
     * @param activity
     */
    protected void show(Activity activity) {
        if (preferencesManager.isDisplayed(dragGuideViewId))
            return;

        ((ViewGroup) activity.getWindow().getDecorView()).addView(this);

        setReady(true);

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (isFadeAnimationEnabled)
                    AnimationFactory.animateFadeIn(BaseGuideView.this, fadeAnimationDuration, new AnimationListener.OnAnimationStartListener() {
                        @Override
                        public void onAnimationStart() {
                            setVisibility(VISIBLE);
                        }
                    });
                else
                    setVisibility(VISIBLE);
            }
        },delayMillis);

        if(displayTime > 0) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    dismiss();
                }
            }, delayMillis + displayTime);
        }
    }

    /**
     * Dismiss Material Intro View
     */
    public void dismiss() {
        handler.removeCallbacksAndMessages(null);
        preferencesManager.setDisplayed(dragGuideViewId);
        AnimationFactory.animateFadeOut(this, fadeAnimationDuration, new AnimationListener.OnAnimationEndListener() {
            @Override
            public void onAnimationEnd() {
                setVisibility(GONE);
                removeMaterialView();

                if (mPerformedListener != null)
                    mPerformedListener.onPerformed(dragGuideViewId);
            }
        });
    }

    private void removeMaterialView(){
        if(getParent() != null )
            ((ViewGroup) getParent()).removeView(this);
    }

    /**
     * locate info card view above/below the
     * circle. If circle's Y coordiante is bigger than
     * Y coordinate of root view, then locate cardview
     * above the circle. Otherwise locate below.
     */
    protected void setInfoLayout() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                isLayoutCompleted = true;

                showInfo();
            }
        });
    }


    /**
     * SETTERS
     */

    protected void setMaskColor(int maskColor) {
        this.maskColor = maskColor;
    }

    protected void setDelay(int delayMillis) {
        this.delayMillis = delayMillis;
    }

    protected void enableFadeAnimation(boolean isFadeAnimationEnabled) {
        this.isFadeAnimationEnabled = isFadeAnimationEnabled;
    }

    protected void setReady(boolean isReady) {
        this.isReady = isReady;
    }

    protected void setTarget(Target target) {
        targetView = target;
    }

    protected void setMainView(Target main) {
        mainView = main;
    }

    protected void setPadding(int padding) {
        this.padding = padding;
    }

    protected void setDismissOnTouch(boolean dismissOnTouch) {
        this.dismissOnTouch = dismissOnTouch;
    }

    protected void enableInfoDialog(boolean isInfoEnabled) {
        this.isInfoEnabled = isInfoEnabled;
    }

    protected void setImageRes(int imageRes){
        this.imageRes = imageRes;
    }

    protected void setUsageId(String dragGuideViewId) {
        this.dragGuideViewId = dragGuideViewId;
    }

    protected void setListener(OnGuidePerformedListener materialIntroListener) {
        this.mPerformedListener = materialIntroListener;
    }

    protected void setPerformClick(boolean isPerformClick){
        this.isPerformClick = isPerformClick;
    }

    protected void setCanAudoDismiss(int time) {
        this.displayTime = time;
    }

}